package znet

import (
	"errors"
	"fmt"
	"io"
	"net"
	"zinx/ziface"
)

type Connection struct {
	//这里放置属性
	//当前连接的socket TCP套接字
	Conn *net.TCPConn
	//当前连接的ID 也可以称作为SessionID，ID全局唯一
	ConnID uint32
	//链接状态
	isClosed bool
	// //处理业务方法API
	// handleAPI ziface.HandleFunc
	//该连接的处理方法router
	// Router ziface.IRouter

	//消息的管理MsgId和对应的处理业务API的关系
	MsgHandler ziface.IMsgHandle
	//告知当前连接退出/停止的channel
	ExitChan chan bool
}

//初始化连接模块


	
func NewConntion(conn *net.TCPConn, connID uint32, msgHandler ziface.IMsgHandle) *Connection{
	c := &Connection{
		//初始化Conn属性
		Conn:     conn,
		ConnID:   connID,
		isClosed: false,
		// Router:   router,
		MsgHandler: msgHandler,
		ExitChan: make(chan bool,1), //创建channel的格式如下：make(chan 元素类型, [缓冲大小])
	}
	return c
}

func (c *Connection) StartReader() {
	fmt.Println("Reader Goroutine is  running")
	defer fmt.Println(c.RemoteAddr().String(), " conn reader exit!")
	//都结束了，当然也就要stop了
	defer c.Stop()
	//读客户端数据，最大的字节数
	for {
		/*
			// buf := make([]byte, 512)
			buf := make([]byte, 515)
			_, err := c.Conn.Read(buf)
			if err != nil {
				fmt.Println("recv buf err ", err)
				continue //cotinue是为了继续读，而不是直接跳出循环
			}
		*/

		// 创建一个拆包解包对象
		dp := NewDataPack()

		//读取客户端Msg Head的二进制流8 个字节
		headData := make([]byte, dp.GetHeadLen())
		if _, err := io.ReadFull(c.GetTCPConnection(), headData); err != nil {
			fmt.Println("read msg head error ", err)
			continue
		}
		//拆包，得到msgid 和 datalen 放在msg中
		msg, err := dp.Unpack(headData)
		if err != nil {
			fmt.Println("unpack error ", err)
			continue
		}
		//根据 dataLen 读取 data，放在msg.Data中
		var data []byte
		if msg.GetDataLen() > 0 {
			data = make([]byte, msg.GetDataLen())
			if _, err := io.ReadFull(c.GetTCPConnection(), data); err != nil {
				fmt.Println("read msg data error ", err)
				continue
			}
		}
		msg.SetData(data) //设计消息内容
		// //调用API            有router了，这里不需要了
		// if err := c.handleAPI(c.Conn,buf,cnt); err!=nil{
		// 	fmt.fmt.Println("ConnID ",c.ConnID,"handle is error",err)

		//打到当前的request请求数据
		req := Request{
			conn: c,
			msg:  msg,
		}
		// //从路由Routers 中找到注册绑定Conn的对应Handle
		// go func(request ziface.IRequest) {
		// 	//执行注册的路由方法
		// 	c.Router.PreHandle(request)
		// 	c.Router.Handle(request)
		// 	c.Router.PostHandle(request)
		// }(&req)
		//根据绑定好的id找到对应的处理api的业务，执行，不该只是上面的c.Router这一个路由方法了
			go c.MsgHandler.DoMsgHandler(&req)
	}

}

func (c *Connection) Start() {
	fmt.Println("Conn Start()... ConnID=", c.ConnID)
	//两个goroutine，分别处理读、写
	//启动从当前连接的读数据的业务
	go c.StartReader()

}

func (c *Connection) Stop() {
	fmt.Println("Conn Stop()... ConnID=", c.ConnID)
	//如果已经关闭
	if c.isClosed == true {
		return
	}
	//关闭socket链接
	c.Conn.Close()
	//回收资源
	close(c.ExitChan)

}

//从当前连接获取原始的socket TCPConn
func (c *Connection) GetTCPConnection() *net.TCPConn {
	return c.Conn
}

//获取当前连接ID
func (c *Connection) GetConnID() uint32 {
	return c.ConnID
}

//获取远程客户端地址信息
func (c *Connection) RemoteAddr() net.Addr {
	return c.Conn.RemoteAddr()
}

//提供一个sendmsg方法，将我们要发送给客户端的数据，先进行封包，再发送
// 现在我们已经将拆包的功能集成到Zinx中了，但是使用Zinx的时候，如果我们希望给用户返回一个TLV格式的数据，
// 总不能每次都经过这么繁琐的过程，所以我们应该给Zinx提供一个封包的接口，供Zinx发包使用。
func (c *Connection) SendMsg(msgId uint32, data []byte) error {
	if c.isClosed == true {
		return errors.New("Connection closed when send msg")
	}
	//将data封包，并且发送
	dp := NewDataPack() //dp得到的是一个空结构体的地址
	msg, err := dp.Pack(NewMsgPackage(msgId, data))
	if err != nil {
		fmt.Println("Pack error msg id = ", msgId)
		return errors.New("Pack error msg ")
	}
	//将数据发送到客户端
	if _, err := c.Conn.Write(msg); err != nil {
		fmt.Println("Write msg id ", msgId, " error ")
		return errors.New("conn Write error")
	}

	return nil
}
